package com.atguigu.gmall.item.service.impl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.feign.product.ProductSkuDetailFeignClient;
import com.atguigu.gmall.feign.search.SearchFeignClients;
import com.atguigu.gmall.starter.cache.annotation.MallCache;
import com.atguigu.gmall.starter.cache.service.CacheService;
import com.atguigu.gmall.product.entity.SkuImage;
import com.atguigu.gmall.product.entity.SpuSaleAttr;
import com.atguigu.gmall.product.vo.CategoryTreeVo;
import com.atguigu.gmall.product.entity.SkuInfo;
import com.atguigu.gmall.product.vo.SkuDetailVo.CategoryViewDTO;

import com.atguigu.gmall.item.service.SkuDetailService;
import com.atguigu.gmall.product.vo.SkuDetailVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class SkuDetailServiceImpl implements SkuDetailService {

    @Autowired
    ProductSkuDetailFeignClient skuDetailFeignClient;

    @Autowired
    ThreadPoolExecutor poolExecutor;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    SearchFeignClients searchFeignClients;



    @Autowired
    CacheService cacheService;

    Map<Long, SkuDetailVo> cache = new ConcurrentHashMap<>();

    ReentrantLock lock = new ReentrantLock();


    @Autowired
    RedissonClient redissonClient;


    @MallCache(
            cacheKey = RedisConst.SKU_DETAIL_CACHE + "#{#args[0]}",
            BitMapName = RedisConst.SKUID_BITMAP,
            BitMapKey = "#{#args[0]}",
            LockKey = RedisConst.LOCK_SKUID + "#{#args[0]}",
            expirationTime = 7,
            TimeType = TimeUnit.DAYS)
    @Override
    public SkuDetailVo getSkuDetailData(Long skuId) {
        SkuDetailVo detailVo = getDataFromRpc(skuId);
        return detailVo;
    }

    @Override
    public void upHotScore(Long skuId) {
        CompletableFuture.runAsync(()->{
            Long score = redisTemplate.opsForValue().increment("sku:hotscore" + skuId);
            if (score%100==0){
                searchFeignClients.updateHotScore(skuId,score);
            }
        },poolExecutor);
    }




   /* public SkuDetailVo getSkuDetailDataWithDistributedLock(Long skuId) {

        SkuDetailVo returnValue = null;
        //先从缓存中查询
        returnValue = cacheService.getFromCache(skuId);
        if (returnValue != null) {
            return returnValue;
        }
        //查询不到
        //先位图判断
        boolean contain = cacheService.mightContain(skuId);
        if (!contain) {
            return null;
        }

        //回源 加锁
        RLock lock = redissonClient.getLock(RedisConst.LOCK_SKUID + skuId);

        boolean tryLock = false;
        try {

            tryLock = lock.tryLock();
            if (tryLock) {
                //加锁成功
                returnValue = getDataFromRpc(skuId);

                //将数据添加到缓存
                cacheService.saveData(skuId, returnValue);

                return returnValue;

            } else {
                //加锁失败睡眠
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return cacheService.getFromCache(skuId);
            }

        } finally {
            if (tryLock) {
                try {
                    lock.unlock();
                } catch (Exception e) {

                }
            }
        }
    }

    public SkuDetailVo getSkuDetailDataWithLocalLock(Long skuId) {

        //分布式锁 加锁
        // String uuid = lockService.Lock();

        SkuDetailVo returnValue = null;
        log.info("商品详情查询开始...");
        //先查缓存
        returnValue = cacheService.getFromCache(skuId);

        if (returnValue == null) {
            //位图判断

            boolean contain = cacheService.mightContain(skuId);
            if (!contain) {
                log.info("bitmap没有，疑似攻击请求，直接打回");
                return null;
            }
            //回源
            log.info("bitmap有，准备回源。需要加锁防止击穿");
            boolean tryLock = this.lock.tryLock();
            if (tryLock) {
                log.info("加锁成功...正在回源");
                returnValue = getDataFromRpc(skuId);
                cacheService.saveData(skuId, returnValue);
                this.lock.unlock();
            } else {
                try {
                    log.info("加锁失败...稍等直接返回缓存数据");
                    TimeUnit.MILLISECONDS.sleep(500);
                    returnValue = cacheService.getFromCache(skuId);
                } catch (InterruptedException e) {
                }
            }
        }


        //分布式锁 解锁
        //lockService.unLock(uuid);


        return returnValue;
    }

    public SkuDetailVo getSkuDetailDataNullSave(Long skuId) {

        String json = redisTemplate.opsForValue().get("sku:info" + skuId);


        if (StringUtils.isEmpty(json)) {
            //缓存中没有 会员
            SkuDetailVo result = getDataFromRpc(skuId);
            String jsonDate = "x";
            if (result != null) {
                jsonDate = JSON.toJSONString(result);
            }

            redisTemplate.opsForValue().set("sku:info" + skuId, jsonDate, 7, TimeUnit.DAYS);
            return result;
        }
        //缓存中有
        if ("x".equals(json)) {
            log.info("疑似攻击请求");
            return null;
        }
        SkuDetailVo result = JSON.parseObject(json, SkuDetailVo.class);
        return result;

    }


    public SkuDetailVo getSkuDetailDataLocalLock(Long skuId) {

        SkuDetailVo result = cache.get(skuId);

        if (result == null) {
            log.info("商品详情：缓存未命中，正在回源");

            //回源 回到数据源头进行查询
            result = getDataFromRpc(skuId);

            cache.put(skuId, result);
        } else {

            log.info("商品详情：缓存命中");

        }

        return result;
    }
*/

    private SkuDetailVo getDataFromRpc(Long skuId) {
        //获取商品详情数据
        SkuDetailVo data = new SkuDetailVo();

        //1、异步 商品详情+图片
        CompletableFuture<SkuInfo> skuInfoFuture = CompletableFuture.supplyAsync(() -> {

            log.info("详情：skuinfo");
            SkuInfo skuInfo = skuDetailFeignClient.getSkuInfo(skuId).getData();
            return skuInfo;
        }, poolExecutor);


        CompletableFuture<Void> SkuImageFuture = skuInfoFuture.thenAcceptAsync(res -> {
            log.info("图片：skuimage");
            if (res == null) return;
            List<SkuImage> skuImages = skuDetailFeignClient.getSkuImages(skuId).getData();
            res.setSkuImageList(skuImages);
            data.setSkuInfo(res);
        }, poolExecutor);

        //2、异步 当前商品精确完整分类信息；
        CompletableFuture<Void> categoryFuture = skuInfoFuture.thenAcceptAsync(res -> {
            log.info("分类：category");
            if (res == null) return;
            CategoryTreeVo categoryTreeVo = skuDetailFeignClient.getCategoryTreeWithC3Id(res.getCategory3Id()).getData();
            //数据模型转换
            CategoryViewDTO viewDTO = convertToCategoryViewDTO(categoryTreeVo);
            data.setCategoryView(viewDTO);

        }, poolExecutor);

        //3、实时价格
        CompletableFuture<Void> priceFuture = CompletableFuture.runAsync(() -> {

            log.info("价格：price");
            try {
                BigDecimal price = skuDetailFeignClient.getPrice(skuId).getData();
                data.setPrice(price);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, poolExecutor);

        //4、销售属性;
        CompletableFuture<Void> spuSaleAttrFuture = skuInfoFuture.thenAcceptAsync(res -> {

            log.info("销售属性：saleAttr");
            if (res == null) return;
            List<SpuSaleAttr> spuSaleAttrs = skuDetailFeignClient.getSpuSaleAttr(res.getSpuId(), skuId).getData();
            data.setSpuSaleAttrList(spuSaleAttrs);
        }, poolExecutor);


        CompletableFuture<Void> SkuValueFuture = skuInfoFuture.thenAcceptAsync(res -> {
            //5、当前sku的所有兄弟们的所有组合可能性。
            log.info("组合：valueJson");
            if (res == null) return;
            String json = skuDetailFeignClient.getValuesSkuJson(res.getSpuId()).getData();
            data.setValuesSkuJson(json);
        }, poolExecutor);

        CompletableFuture.allOf(skuInfoFuture, SkuImageFuture, categoryFuture, priceFuture, spuSaleAttrFuture, SkuValueFuture).join();
        return data;
    }

    private CategoryViewDTO convertToCategoryViewDTO(CategoryTreeVo categoryTreeVo) {
        CategoryViewDTO viewDTO = new CategoryViewDTO();
        viewDTO.setCategory1Id(categoryTreeVo.getCategoryId());
        viewDTO.setCategory1Name(categoryTreeVo.getCategoryName());

        CategoryTreeVo child1 = categoryTreeVo.getCategoryChild().get(0);
        viewDTO.setCategory2Id(child1.getCategoryId());
        viewDTO.setCategory2Name(child1.getCategoryName());

        CategoryTreeVo child2 = child1.getCategoryChild().get(0);
        viewDTO.setCategory3Id(child2.getCategoryId());
        viewDTO.setCategory3Name(child2.getCategoryName());
        return viewDTO;
    }


}
